﻿using BrightIdeasSoftware;
using ComponentFactory.Krypton.Toolkit;
using PNGInfo.Framework;
using StableDiffusionTools.Controls.KryptonHelper;
using StableDiffusionTools.Forms;
using StableDiffusionTools.Framework;
using StableDiffusionTools.Imaging;
using StableDiffusionTools.Interop;
using StableDiffusionTools.Themes;
using StableDiffusionTools.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;

namespace PNGInfo.Forms
{
    [Export(typeof(IForm))]
    [ExportMetadata("Name", "PNG Info")]
    [ExportMetadata("Image", "pnginfo32")]
    public partial class PNGInfoFrom : KryptonForm, IForm
    {
        public bool Busy { get; protected set; }
        private TypedObjectListView<PNGTag> tolvTags;
        private SettingsManager<PNGInfoSettings> settingsMan = new SettingsManager<PNGInfoSettings>(nameof(PNGInfoSettings), createBackups: false);
        private PNGInfoSettings settings;
        private Framework.FilterType filterType = Framework.FilterType.Tags;
        private string filterString = "";
        private Size filterSize = Size.Empty;
        private ModelFilter tagFilter;
        private ModelFilter sizeFilter;
        private ModelFilter modelFilter;
        private ModelFilter hashFilter;
        private string currentPath;
        private bool unableToCache = false;
        private Image importImage = StableDiffusionTools.Properties.Resources.document_import16;
        private Image cancelImage = BitmapResizer.ResizeBitmap(StableDiffusionTools.Properties.Resources.stop32, new BitmapResizeGDISettings(GDIResizePresent.Default, new Size(16, 16)));
        CancellationTokenSource source = null;
        ShellContextMenu shellContext = new ShellContextMenu();

        public PNGInfoFrom()
        {
            InitializeComponent();
            GlobalTheme.Init();
            buttonSpecTheme.KryptonContextMenu = new KryptonThemeContextMenu();

            Icon = Properties.Resources.pnginfo;
            tsbBrowse.Image = StableDiffusionTools.Properties.Resources.folder16;
            tsbLoad.Image = importImage;
            tsddActions.Image = StableDiffusionTools.Properties.Resources.action16;
            tsbFilter.Image = StableDiffusionTools.Properties.Resources.filter16;
            openToolStripMenuItem.Image = StableDiffusionTools.Properties.Resources.open16;
            openExplorerToolStripMenuItem.Image = StableDiffusionTools.Properties.Resources.openfolder16;
            openPictureviewerToolStripMenuItem.Image = StableDiffusionTools.Properties.Resources.image16;

            settings = settingsMan.LoadSettings();
            imageControl1.SizeMode = settings.FitSize ? StableDiffusionTools.Controls.ImageSizeMode.Fit : StableDiffusionTools.Controls.ImageSizeMode.Zoom;
            filterType = settings.LastFilterType;

            olvTags.FilterMenuBuildStrategy = new FilterMenuBuilder() { MaxObjectsToConsider = 100000000};

            tolvTags = new TypedObjectListView<PNGTag>(olvTags);

            tolvTags.GetColumn("File").AspectGetter += (o) => o?.FileName;
            olvColumnFile.Renderer = new BaseRenderer() { UseGdiTextRendering = false };

            tolvTags.GetColumn("Tags").AspectGetter += (o) => o?.TagData;
            olvColumnTags.Renderer = new BaseRenderer() { UseGdiTextRendering = false };

            tolvTags.GetColumn("Size").AspectGetter += (o) => o != null ? $"{o.Size.Width}x{o.Size.Height}" : "";
            olvColumnSize.Renderer = new BaseRenderer() { UseGdiTextRendering = false };

            tolvTags.GetColumn("Model").AspectGetter += (o) => o != null ? $"{GetModelNameFromHash(o)}" : "";
            olvColumnModel.Renderer = new BaseRenderer() { UseGdiTextRendering = false };

            tolvTags.GetColumn("Hash").AspectGetter += (o) => o?.ModelHash;
            olvColumnHash.Renderer = new BaseRenderer() { UseGdiTextRendering = false };

            tagFilter = new ModelFilter(delegate (object x) {
                var tag = (PNGTag)x;
                return tag.FullTagData.IndexOf(filterString, StringComparison.OrdinalIgnoreCase) != -1;
            });

            sizeFilter= new ModelFilter(delegate (object x) {
                var tag = (PNGTag)x;
                return tag.Size.Equals(filterSize);
            });

            modelFilter = new ModelFilter(delegate (object x) {
                var tag = x as PNGTag;
                if (tag?.ModelName == null)
                    return false;

                return tag.ModelName.IndexOf(filterString, StringComparison.OrdinalIgnoreCase) != -1;
            });

            hashFilter = new ModelFilter(delegate (object x) {
                var tag = x as PNGTag;
                if (tag?.ModelHash == null)
                    return false;

                return tag.ModelHash.IndexOf(filterString, StringComparison.OrdinalIgnoreCase) != -1;
            });

            FormClosing += (s, e) =>
            {
                imageControl1.Image = null;
                settings.FitSize = imageControl1.SizeMode == StableDiffusionTools.Controls.ImageSizeMode.Fit;
                settings.LastFilterType = filterType;
                settings.LastSidePanelWidth = kryptonSplitContainer1.ClientSize.Width - kryptonSplitContainer1.Panel1.ClientSize.Width;
                settings.LastSidePanelHeight = kryptonSplitContainer2.SplitterDistance;
                settingsMan.SaveSettings(settings);
            };

            if (settings.LastSidePanelWidth != -1)
                kryptonSplitContainer1.SplitterDistance = kryptonSplitContainer1.ClientSize.Width - settings.LastSidePanelWidth;
            if (settings.LastSidePanelHeight != -1)
                kryptonSplitContainer2.SplitterDistance = settings.LastSidePanelHeight;
        }

        private async void tstbPath_KeyDown(object sender, KeyEventArgs e)
        {
            if (!Busy && e.KeyCode == Keys.Enter)
            {
                e.SuppressKeyPress = true;
                PathInfo info = ExtendedPathInfo.GetPathInfo(tstbPath.Text);
                if (info == PathInfo.Directory)
                {
                    await LoadPath(tstbPath.Text);
                }
                else if (info == PathInfo.File)
                {
                    await LoadPaths(new string[] { tstbPath.Text }, true);
                }
                else if (info == PathInfo.NotFound)
                {
                    ClearTags();
                    tsslStatus.Text = $"Cleared";
                    tspbProgress.Value = 0;
                }
            }
        }

        private void tsbBrowse_MouseUp(object sender, MouseEventArgs e)
        {
            var folder = new FolderSelectDialog();
            if(!string.IsNullOrEmpty(settings.LastPath))
                folder.InitialDirectory = settings.LastPath;

            if (folder.ShowDialog() && !IsDisposed)
            {
                settings.LastPath = tstbPath.Text = folder.FileName;
            }
        }

        private async void tsbLoad_MouseUp(object sender, MouseEventArgs e)
        {
            if (!Busy)
            {
                PathInfo info = ExtendedPathInfo.GetPathInfo(tstbPath.Text);
                if (info == PathInfo.Directory)
                {
                    await LoadPath(tstbPath.Text);
                }
                else if (info == PathInfo.File)
                {
                    await LoadPaths(new string[] { tstbPath.Text }, true);
                }
                else if (info == PathInfo.NotFound)
                {
                    ClearTags();
                    tsslStatus.Text = $"Cleared";
                    tspbProgress.Value = 0;
                }
            }
            else
            {
                source?.Cancel();
            }
        }

        private void olvTags_SelectedIndexChanged(object sender, EventArgs e)
        {
            PNGTag tag = tolvTags.SelectedObject;
            if (tag == null)
            {
                kryptonTBTags.Clear();
                imageControl1.Image = null;
            }
            else
            {
                kryptonTBTags.Text = tag.FullTagData;
                kryptonTBTags.Refresh();
                try
                {
                    imageControl1.SetImage(ImageUtil.LoadBitmap(tag.FullName), true);
                }
                catch (Exception)
                {
                    imageControl1.Image = null;
                }
            }
        }

        private void olvTags_DragEnter(object sender, DragEventArgs e)
        {
            if (!Busy && e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private async void olvTags_DragDrop(object sender, DragEventArgs e)
        {
            if (!Busy)
            {
                if (e.Data.GetDataPresent(DataFormats.FileDrop))
                {
                    string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                    if (files.Length == 1 && ExtendedPathInfo.GetPathInfo(files[0]) == PathInfo.Directory)
                    {
                        tstbPath.Text = files[0];

                        await LoadPath(files[0]);
                    }
                    else
                    {
                        await LoadPaths(files, false);
                    }
                }
            }
        }

        private async void olvTags_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                olvTags.DeselectAll();
                e.SuppressKeyPress = true;
            }
            else if (e.KeyCode == Keys.V && e.Control)
            {
                if (Clipboard.ContainsFileDropList())
                {
                    e.SuppressKeyPress = true;
                    string[] files = (string[])Clipboard.GetData(DataFormats.FileDrop);
                    if (files.Length == 1 && ExtendedPathInfo.GetPathInfo(files[0]) == PathInfo.Directory)
                    {
                        tstbPath.Text = files[0];
                        await LoadPath(files[0]);
                    }
                    else
                    {
                        await LoadPaths(files, false);
                    }
                }
            }
        }

        private void contextMenuStrip1_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            bool hasSelection = tolvTags.SelectedObject != null;
            if (hasSelection && ModifierKeys.HasFlag(Keys.Control))
            {
                e.Cancel = true;
                shellContext.ShowContextMenu(new FileInfo[] { new FileInfo(tolvTags.SelectedObject.FullName) }, MousePosition);
            }
            else if (!hasSelection)
            {
                e.Cancel = true;
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ProcessUtil.LaunchAsync(tolvTags.SelectedObject?.FullName);
        }

        private void openExplorerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExplorerUtil.Open(tolvTags.SelectedObject?.FullName, !ModifierKeys.HasFlag(Keys.Shift));
        }

        private void openPictureviewerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExplorerUtil.OpenWithPictureViewer(tolvTags.SelectedObject?.FullName);
        }

        private void tsbFilter_MouseUp(object sender, MouseEventArgs e)
        {
            if(olvTags.ModelFilter == null)
                filterString = "";

            using (var filterDialog = new InputDialogWithEnum<Framework.FilterType>("Filter list by keyword", "Filter", filterString, true, "By type", filterType))
            {
                if (filterDialog.ShowDialog() == DialogResult.OK)
                {
                    if (!string.IsNullOrWhiteSpace(filterDialog.Result))
                    {
                        SetFilter(filterDialog.Result, filterDialog.ResultEnum);
                    }
                    else
                    {
                        RemoveFilter(filterDialog.ResultEnum);
                    }
                }
            }
        }

        private void tsddActions_DropDownOpening(object sender, EventArgs e)
        {
            string currPath = "";
            string txtPath = "";
            if (ExtendedPathInfo.GetPathInfo(currentPath) == PathInfo.Directory)
                currPath = currentPath;

            string currCachePath = "";
            if (!string.IsNullOrEmpty(currPath))
            {
                string cachePathTest = Path.Combine(currPath, "pnginfo_cache.xml");
                if (ExtendedPathInfo.GetPathInfo(cachePathTest) == PathInfo.File)
                {
                    currCachePath = cachePathTest;
                }
            }


            if (ExtendedPathInfo.GetPathInfo(tstbPath.Text) == PathInfo.Directory)
                txtPath = tstbPath.Text;
            string txtCachePath = "";
            if (!string.IsNullOrEmpty(txtPath))
            {
                string cachePathTest = Path.Combine(txtPath, "pnginfo_cache.xml");
                if (ExtendedPathInfo.GetPathInfo(cachePathTest) == PathInfo.File)
                {
                    txtCachePath = cachePathTest;
                }
            }

            if (!string.IsNullOrEmpty(currCachePath))
            {
                createCacheToolStripMenuItem.Enabled = true;
                createCacheToolStripMenuItem.Text = "Save Cache";
            }
            else if (!string.IsNullOrEmpty(currPath))
            {
                createCacheToolStripMenuItem.Enabled = !unableToCache;
                createCacheToolStripMenuItem.Text = "Create Cache";
            }
            else
            {
                createCacheToolStripMenuItem.Enabled = false;
                createCacheToolStripMenuItem.Text = "Create Cache";
            }

            if (!string.IsNullOrEmpty(txtCachePath))
            {
                loadCacheToolStripMenuItem.Enabled = true;
            }
            else
            {
                loadCacheToolStripMenuItem.Enabled = false;
            }
        }

        private void createCacheToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (ExtendedPathInfo.GetPathInfo(currentPath) == PathInfo.Directory)
            {
                string pngInfoPath = Path.Combine(currentPath, "pnginfo_cache.xml");
                if (File.Exists(pngInfoPath) && ConfirmationDialog.ShowDialogIf(this, ref settings.SaveCacheConfirmation, "You are about to overwrite the existing cache, are you sure?") != DialogResult.Yes)
                    return;

                var emptyNamespace = new System.Xml.Serialization.XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
                var serializer = new System.Xml.Serialization.XmlSerializer(typeof(PNGTagsCache));
                using (var writer = new StreamWriter(pngInfoPath, false))
                using (var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true, NewLineHandling = NewLineHandling.Entitize }))
                {
                    serializer.Serialize(xmlWriter, new PNGTagsCache() { Tags = tolvTags.Objects as List<PNGTag> }, emptyNamespace);
                }
            }
        }

        private async void loadCacheToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (ExtendedPathInfo.GetPathInfo(tstbPath.Text) == PathInfo.Directory)
            {
                try
                {
                    Progress<string> progress = new Progress<string>();
                    void progressChanged(object s, string c)
                    {
                        tsslStatus.Text = c;
                        tspbProgress.Value = 50;
                    }
                    progress.ProgressChanged += progressChanged;

                    tsslStatus.Text = $"Loading cache...";
                    tspbProgress.Value = 0;

                    PNGTagsCache result = await Task.Run(() =>
                    {
                        PNGTagsCache tagsCache;
                        var serializer = new System.Xml.Serialization.XmlSerializer(typeof(PNGTagsCache));
                        using (var reader = new StreamReader(Path.Combine(tstbPath.Text, "pnginfo_cache.xml")))
                        using (var xmlReader = XmlReader.Create(reader, new XmlReaderSettings() { }))
                        {
                            tagsCache = (PNGTagsCache)serializer.Deserialize(xmlReader);
                        }
                        ((IProgress<string>)progress).Report($"Populating {tagsCache.Tags.Count} PNG files...");
                        DirectoryInfo root = new DirectoryInfo(tstbPath.Text);
                        tagsCache.Populate(root.FullName);
                        return tagsCache;
                    });

                    ClearTags();
                    AssignTags(result.Tags);

                    progress.ProgressChanged -= progressChanged;
                    tsslStatus.Text = $"Loaded {result.Tags.Count} PNG files";
                    tspbProgress.Value = 100;

                    currentPath = tstbPath.Text;
                    unableToCache = false;
                }
                catch (Exception ex)
                {

                }
            }
        }

        private string GetModelNameFromHash(PNGTag o)
        {
            if (o.ModelName == null)
            {
                if (o.ModelHash != null)
                {
                    if (ModelHasher.ModelHasherState.State.TryGetModelHashByHash(o.ModelHash, out ModelHasher.Framework.ModelHash modelHash))
                    {
                        o.ModelName = modelHash.Name;
                    }
                }
            }
            else
            {
                return o.ModelName;
            }

            return null;
        }

        public async Task LoadPaths(string[] paths, bool clearExisting)
        {
            source = new CancellationTokenSource();
            SetLoading(true);

            Progress<CountProgress> progress = new Progress<CountProgress>();
            void progressChanged(object s, CountProgress c)
            {
                tsslStatus.Text = $"Loading... {c.Completed} PNG files found";
                tspbProgress.Value = c.GetProgressInt();
            }
            progress.ProgressChanged += progressChanged;

            List<PNGTag> tags = await LoadPaths(paths, progress, settings.MaxFileReadThreads, source.Token);

            if(clearExisting)
                ClearTags();
            AssignTags(tags);

            progress.ProgressChanged -= progressChanged;
            if (!source.Token.IsCancellationRequested)
            {
                tsslStatus.Text = $"Loaded {tags.Count} PNG files";
                tspbProgress.Value = 100;
                unableToCache = true;
                tstbPath.Text = "";
            }
            else
            {
                tsslStatus.Text = $"Load was canceled";
                tspbProgress.Value = 0;
            }

            SetLoading(false);
        }

        private async Task<List<PNGTag>> LoadPaths(string[] paths, IProgress<CountProgress> progress = null, int maxDegreeOfParallelism = 1, CancellationToken cancellation = default(CancellationToken))
        {
            List<PNGTag> resultTags = await Task.Run(() =>
            {
                object locker = new object();
                int counter = 0;
                int errored = 0;
                ConcurrentBag<PNGTag> tags = new ConcurrentBag<PNGTag>();
                Queue<string> dirs = new Queue<string>(paths);
                List<string> pngs = new List<string>();
                while (dirs.Count > 0)
                {
                    string item = dirs.Dequeue();
                    var info = ExtendedPathInfo.GetPathInfo(item);
                    if (info == PathInfo.Directory)
                    {
                        string[] itemDirs = Directory.GetDirectories(item);
                        for (int i = 0; i < itemDirs.Length; i++)
                        {
                            dirs.Enqueue(itemDirs[i]);
                        }

                        string[] files = Directory.GetFiles(item);
                        for (int i = 0; i < files.Length; i++)
                        {
                            if (cancellation.IsCancellationRequested)
                                break;

                            if (Path.GetExtension(files[i]).Equals(".png", StringComparison.InvariantCultureIgnoreCase))
                            {
                                pngs.Add(files[i]);
                            }
                        }
                    }
                    else if(info == PathInfo.File)
                    {
                        if (Path.GetExtension(item).Equals(".png", StringComparison.InvariantCultureIgnoreCase))
                        {
                            pngs.Add(item);
                        }
                    }
                }

                //string root = new DirectoryInfo(path).FullName;
                Parallel.ForEach(pngs, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, (t) =>
                {
                    if (cancellation.IsCancellationRequested)
                        return;

                    try
                    {
                        PNGTag tag = new PNGTag(t, null);
                        tags.Add(tag);
                    }
                    catch (Exception)
                    {
                        errored++;
                    }

                    if (progress != null)
                    {
                        int currentCount = Interlocked.Increment(ref counter);
                        if (currentCount % 100 == 0)
                        {
                            lock (locker)
                            {
                                progress.Report(new CountProgress(pngs.Count, currentCount));
                            }
                        }
                    }
                });


                if (cancellation.IsCancellationRequested)
                    return new List<PNGTag>();

                return tags.OrderBy((t) => t.FullName, new CustomComparer<string>(CompareUtil.CompareNatural)).ToList();
            });
            return resultTags;
        }

        public async Task LoadPath(string path)
        {
            source = new CancellationTokenSource();
            SetLoading(true);

            Progress<CountProgress> progress = new Progress<CountProgress>();
            void progressChanged(object s, CountProgress c)
            {
                tsslStatus.Text = $"Loading... {c.Completed} PNG files found";
                tspbProgress.Value = c.GetProgressInt();
            }
            progress.ProgressChanged += progressChanged;

            List<PNGTag> tags = await LoadPath(path, progress, settings.MaxFileReadThreads, source.Token);

            ClearTags();
            AssignTags(tags);

            progress.ProgressChanged -= progressChanged;
            if (!source.Token.IsCancellationRequested)
            {
                tsslStatus.Text = $"Loaded {tags.Count} PNG files";
                tspbProgress.Value = 100;

                currentPath = path;
                unableToCache = false;
            }
            else
            {
                tsslStatus.Text = $"Load was canceled";
                currentPath = "";
                tspbProgress.Value = 0;
            }

            SetLoading(false);
        }

        private async Task<List<PNGTag>> LoadPath(string path, IProgress<CountProgress> progress = null, int maxDegreeOfParallelism = 1, CancellationToken cancellation = default(CancellationToken))
        {
            settings.LastPath = path;

            List<PNGTag> resultTags = await Task.Run(() =>
            {
                object locker = new object();
                int counter = 0;
                int errored = 0;
                ConcurrentBag<PNGTag> tags = new ConcurrentBag<PNGTag>();
                Queue<string> dirs = new Queue<string>(new string[] { path });
                List<string> pngs = new List<string>();
                while (dirs.Count > 0)
                {
                    string item = dirs.Dequeue();
                    var info = ExtendedPathInfo.GetPathInfo(item);
                    if (info == PathInfo.Directory)
                    {
                        string[] itemDirs = Directory.GetDirectories(item);
                        for (int i = 0; i < itemDirs.Length; i++)
                        {
                            dirs.Enqueue(itemDirs[i]);
                        }
                    }
                    string[] files = Directory.GetFiles(item);
                    for (int i = 0; i < files.Length; i++)
                    {
                        if (cancellation.IsCancellationRequested)
                            break;

                        if (Path.GetExtension(files[i]).Equals(".png", StringComparison.InvariantCultureIgnoreCase))
                        {
                            pngs.Add(files[i]);
                        }
                    }
                }

                string root = new DirectoryInfo(path).FullName;
                Parallel.ForEach(pngs, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, (t) =>
                {
                    if (cancellation.IsCancellationRequested)
                        return;

                    try
                    {
                        PNGTag tag = new PNGTag(t, root);
                        tags.Add(tag);
                    }
                    catch (Exception)
                    {
                        errored++;
                    }

                    if (progress != null)
                    {
                        int currentCount = Interlocked.Increment(ref counter);
                        if (currentCount % 100 == 0)
                        {
                            lock (locker)
                            {
                                progress.Report(new CountProgress(pngs.Count, currentCount));
                            }
                        }
                    }
                });


                if (cancellation.IsCancellationRequested)
                    return new List<PNGTag>();

                return tags.OrderBy((t) => t.FullName, new CustomComparer<string>(CompareUtil.CompareNatural)).ToList();
            });
            return resultTags;
        }

        private void SetFilter(string filterOn, Framework.FilterType type)
        {
            filterString = filterOn;
            filterType = type;
            switch (type)
            {
                case Framework.FilterType.Tags:
                    olvTags.ModelFilter = tagFilter;
                    break;
                case Framework.FilterType.Size:
                    var split = filterOn.Split(new char[] { 'x', 'X' }, StringSplitOptions.RemoveEmptyEntries);
                    if (split.Length == 2 && int.TryParse(split[0], out int w) && int.TryParse(split[1], out int h))
                        filterSize = new Size(w, h);
                    else
                        filterSize = Size.Empty;

                    olvTags.ModelFilter = sizeFilter;
                    break;
                case Framework.FilterType.Model:
                    olvTags.ModelFilter = modelFilter;
                    break;
                case Framework.FilterType.Hash:
                    olvTags.ModelFilter = hashFilter;
                    break;
                default:
                    break;
            }

        }

        private void RemoveFilter() => RemoveFilter(filterType);
        private void RemoveFilter(Framework.FilterType type)
        {
            filterType = type;
            filterString = "";
            filterSize = Size.Empty;
            olvTags.ModelFilter = null;
        }

        private void SetLoading(bool loading)
        {
            toolStrip1.SuspendLayout();
            if (loading)
            {
                tsbLoad.Image = cancelImage;
                tsbLoad.Text = "Cancel";
            }
            else
            {
                tsbLoad.Image = importImage;
                tsbLoad.Text = " Load ";
            }
            tsbBrowse.Enabled = !loading;
            tsddActions.Enabled = !loading;
            tsbFilter.Enabled = !loading;
            toolStrip1.ResumeLayout();
            toolStrip1.PerformLayout();
            Busy = loading;
        }

        private void ClearTags()
        {
            olvTags.SuspendLayout();
            olvTags.BeginUpdate();
            olvTags.ClearObjects();
            RemoveFilter();
            olvTags.ResumeLayout();
            olvTags.EndUpdate();
        }

        private void AssignTags(List<PNGTag> tags)
        {
            olvTags.SuspendLayout();
            olvTags.BeginUpdate();
            olvTags.AddObjects(tags);
            olvTags.ResumeLayout();
            olvTags.EndUpdate();
        }

        public bool CloseFromTaskTray()
        {
            if (Disposing || IsDisposed)
                return true;

            Close();
            return true;
        }

 
    }
}
